///////////////////////////////////////////////////////////////////////
//
// NO_TypeID.h
//
///////////////////////////////////////////////////////////////////////

///////////////////////////////////////////////////////////////////////
#ifndef NO_TYPE_ID_H
#define NO_TYPE_ID_H

///////////////////////////////////////////////////////////////////////
#include "NO_Type.h"

//////////////////////////////////////////////////////////////////////////
// Unknown type helper
//////////////////////////////////////////////////////////////////////////
class NO_UnknownType{};

///////////////////////////////////////////////////////////////////////
// TypeID
///////////////////////////////////////////////////////////////////////
class NO_DLL_TAL NO_HelperTypeID
{
protected:
	//////////////////////////////////////////////////////////////////////////
	static NO_Type::InternTypeIter findIntern	(type_info const &);
	static NO_Type::InternTypeIter endIntern	(void);
	
	//////////////////////////////////////////////////////////////////////////
	static NO_Type::GlobalTypeIter findGlobal	(NO_UInt32);
	static NO_Type::GlobalTypeIter findGlobal	(std::string&);
	static NO_Type::GlobalTypeIter findGlobal	(NO_Int8 const *);
	static NO_Type::GlobalTypeIter endGlobal	(void);

	//////////////////////////////////////////////////////////////////////////
	friend class NO_Type;

	//////////////////////////////////////////////////////////////////////////
	static void registerHandler(const type_info &, NO_TypeHandler&);
};

///////////////////////////////////////////////////////////////////////
// TypeID
///////////////////////////////////////////////////////////////////////
template<class T = NO_UnknownType>
class NO_TypeID : private NO_HelperTypeID
{
public:
	//////////////////////////////////////////////////////////////////////////
	static const NO_Type& type(void)				
	{
		if(t){return *t;}
	//	if(test!=t){_asm{int 3};};
		handler.setTypePtrToControl(t);
		NO_HelperTypeID::registerHandler(typeid(T),handler);
	//	test = t;
		return *t;
	}

private:
	//////////////////////////////////////////////////////////////////////////
	static NO_TypeHandler handler;
	static NO_Type* t;
	//static NO_Type* test;
};

//////////////////////////////////////////////////////////////////////////
template <class T> NO_Type* NO_TypeID<T>::t = 0;
//template <class T> NO_Type* NO_TypeID<T>::test = 0;
template <class T> NO_TypeHandler NO_TypeID<T>::handler;

///////////////////////////////////////////////////////////////////////
// TypeID
///////////////////////////////////////////////////////////////////////
template<> 
class NO_DLL_TAL NO_TypeID<NO_UnknownType> : private NO_HelperTypeID
{
public:
	//////////////////////////////////////////////////////////////////////////
	static const NO_Type& type(NO_UInt32 ID);
	static const NO_Type& type(std::string& identifier);
	static const NO_Type& type(const NO_Int8 * identifier);
	static const NO_Type& type(const type_info & rtti);
};

//////////////////////////////////////////////////////////////////////////
// PrivateHelper
//////////////////////////////////////////////////////////////////////////
struct NO_PrivateHelper
{
	NO_PrivateHelper(const NO_Object& obj):data(obj.data){}
	NO_Value* data;
};

//////////////////////////////////////////////////////////////////////////
// typed data get
//////////////////////////////////////////////////////////////////////////

//////////////////////////////////////////////////////////////////////////
template<class T>
T* noGetData(const NO_Object & obj)
{
	NO_ValueImpl<T>* od = dynamic_cast<NO_ValueImpl<T>* >(NO_PrivateHelper(obj).data);	
	if(od){return od->getObject();}

	NO_Object c =  obj.cast(NO_TypeID<T>::type());
	od = dynamic_cast<NO_ValueImpl<T>* >(NO_PrivateHelper(c).data);
	if(od){return od->getObject();}
	
	return 0;
};

//////////////////////////////////////////////////////////////////////////
template<class T>
T* noGetDataException(const NO_Object & obj)
{
	NO_ValueImpl<T>* od = dynamic_cast<NO_ValueImpl<T>* >(NO_PrivateHelper(obj).data);	
	if(od){return od->getObject();}
	
	NO_Object c =  obj.cast(NO_TypeID<T>::type());
	od = dynamic_cast<NO_ValueImpl<T>* >(NO_PrivateHelper(c).data);
	if(od){return od->getObject();}

	throw std::exception("T* noGetDataException(NO_Object const &) failed.");
};

//////////////////////////////////////////////////////////////////////////
template<class T>
T* noGetData(NO_Value & obj)
{
	NO_ValueImpl<T>* od = dynamic_cast<NO_ValueImpl<T>* >(&obj);	
	if(od){return od->getObject();}

	NO_IBase const * base = obj.getDynamicType().findBase(NO_TypeID<T>::type().getID());
	if(!base){return 0;}

	od = dynamic_cast<NO_ValueImpl<T>* >(base->getBase(obj));
	if(od){return od->getObject();}
	
	return 0;
};

//////////////////////////////////////////////////////////////////////////
template<class T>
T* noGetDataException(NO_Value & obj)
{
	NO_ValueImpl<T>* od = dynamic_cast<NO_ValueImpl<T>* >(&obj);	
	if(od){return od->getObject();}
	
	NO_IBase const * base = obj.getDynamicType().findBase(NO_TypeID<T>::type().getID());
	if(!base){return 0;}

	od = dynamic_cast<NO_ValueImpl<T>* >(base->getBase(obj));
	if(od){return od->getObject();}

	throw std::exception("T* noGetDataException(NO_Value &) failed.");
};

//////////////////////////////////////////////////////////////////////////
// typed data set
//////////////////////////////////////////////////////////////////////////

//////////////////////////////////////////////////////////////////////////
template<class T>
NO_Boolean noSetData(NO_Object & no, const T & o)
{
	NO_ValueImpl<T>* nod = dynamic_cast<NO_ValueImpl<T>* >(NO_PrivateHelper(no).data);	
	if(nod){*nod->getObject() = o; return 1;}

	NO_Object c =  no.cast(NO_TypeID<T>::type());
	nod = dynamic_cast<NO_ValueImpl<T>* >(NO_PrivateHelper(c).data);
	if(nod){*nod->getObject() = o; return 1;}
	
	return 0;
};

//////////////////////////////////////////////////////////////////////////
template<class T>
NO_Boolean noSetDataException(NO_Object & no, const T & o)
{
	NO_ValueImpl<T>* nod = dynamic_cast<NO_ValueImpl<T>* >(NO_PrivateHelper(no).data);	
	if(nod){*nod->getObject() = o; return 1;}

	NO_Object c =  no.cast(NO_TypeID<T>::type());
	nod = dynamic_cast<NO_ValueImpl<T>* >(NO_PrivateHelper(c).data);
	if(nod){*nod->getObject() = o; return 1;}
	
	throw std::exception("T* noGetDataException(NO_Object const &) failed.");
};

//////////////////////////////////////////////////////////////////////////
template<class T>
NO_Boolean noSetData(NO_Value & no, const T & o)
{
	NO_ValueImpl<T>* nod = dynamic_cast<NO_ValueImpl<T>* >(&no);	
	if(nod){*nod->getObject() = o; return 1;}

	NO_IBase const * base = obj.getDynamicType().findBase(NO_TypeID<T>::type().getID());
	if(!base){*nod->getObject() = o; return 1;}

	nod = dynamic_cast<NO_ValueImpl<T>* >(base->getBase(obj));
	if(nod){*nod->getObject() = o; return 1;}
	
	return 0;
};

//////////////////////////////////////////////////////////////////////////
template<class T>
NO_Boolean noSetDataException(NO_Value & no, const T & o)
{
	NO_ValueImpl<T>* nod = dynamic_cast<NO_ValueImpl<T>* >(&no);	
	if(nod){*nod->getObject() = o; return 1;}

	NO_IBase const * base = obj.getDynamicType().findBase(NO_TypeID<T>::type().getID());
	if(!base){*nod->getObject() = o; return 1;}

	nod = dynamic_cast<NO_ValueImpl<T>* >(base->getBase(obj));
	if(nod){*nod->getObject() = o; return 1;}
	
	throw std::exception("T* noGetDataException(NO_Value &) failed.");
};

#endif
